#pragma once
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <cstdlib>
#include "Log.hpp"
#include "commd.hpp"
#include "InitAddr.hpp"
#include <signal.h>
using namespace std;

const int default_port = 8888;
const int default_backlog = 5;
class TcpServer;

struct ThreadData{
    ThreadData(const int sockfd, TcpServer* tcp_this, InitAddr& client_addr) 
        :_sockfd(sockfd)
        ,_this(tcp_this)
        ,_client_addr(client_addr)
    {}
    int _sockfd;
    TcpServer* _this;
    InitAddr _client_addr;
};

class TcpServer {
public :
    TcpServer(const int port = default_port) 
        :_port(port)
    {}
    // 初始化服务器
    void Init() {
        // 创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0) {
            // 创建套接字失败
            lg.LogMessage(Fatal, "create socket error, error code: %d, error string: %s", errno, strerror(errno));
            exit(Socket_Err);
        }
        lg.LogMessage(Debug, "create socket success, sockfd: %d", _listensockfd);
        // 填充本地网录信息
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        // 绑定
        int res = bind(_listensockfd, (struct sockaddr*)&local, sizeof local);
        if (res != 0) {
            // 绑定失败
            lg.LogMessage(Fatal, "bind socket error, error code: %d, error string: %s", errno, strerror(errno));
            exit(Bind_Err);
        }
        // 绑定成功
        lg.LogMessage(Debug, "bind socket success!");
        
        // 将套接字设置为监听状态
        res = listen(_listensockfd, default_backlog);
        if (res != 0) {
            // 监听失败
            lg.LogMessage(Fatal, "listensocket error, error code: %d, error string: %s", errno, strerror(errno));
            exit(Listen_Err);
        }
        // 监听成功
        lg.LogMessage(Debug, "listensocket success");
    }

    static void* ThreadRoutine(void* args) {
        // 将本线程分离
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        td->_this->Service(td->_sockfd, td->_client_addr);
    }

    // 提供服务
    void Service(const int sockfd, InitAddr& client_addr) {
        char buffer[1024];
        while (true) {
            // 先读取客户端输入
            int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0) {
                buffer[n] = '\0';
                cout << client_addr.get_Info() << "# " << buffer << endl;

                // 会发消息给客户端
                string echo_string = "[";
                echo_string += buffer;
                echo_string += "]";
                n = send(sockfd, echo_string.c_str(), echo_string.size(), 0);
            } else if (n == 0) {
                // 服务端读到0，表示对端关闭了连接
                lg.LogMessage(Debug, "client %s close……", client_addr.get_Info().c_str());
                break;
            } else {
                break;
            }
        }
    }

    // 启动服务器
    void Start() {
        while (true) {
            // 获取新的套接字
            struct sockaddr_in client;
            socklen_t len = sizeof client;
            int sockfd = accept(_listensockfd, (struct sockaddr*)&client, &len);
            if (sockfd < 0) {
                lg.LogMessage(Fatal, "accept error, error code: %d, error string: %s", errno, strerror(errno));
                exit(Accept_Err);
            }
            InitAddr client_addr(client);
            lg.LogMessage(Debug, "get a new connect, new sockfd: %d, client info: %s", sockfd, client_addr.get_Info().c_str());
            // 提供服务
            // Service(sockfd, client_addr);

            // 创建线程提供服务
            pthread_t tid;
            ThreadData* td = new ThreadData(sockfd, this, client_addr);
            pthread_create(&tid, nullptr, ThreadRoutine, td);

            //pthread_join(tid, nullptr);
        }
    }

    ~TcpServer() {

    }

private :
    int _listensockfd;
    uint16_t _port;
};